package com.briup.pai.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.briup.pai.common.enums.DatasetStatusEnum;
import com.briup.pai.common.enums.ResultCodeEnum;
import com.briup.pai.common.exception.BriupAssert;
import com.briup.pai.convert.DatasetConvert;
import com.briup.pai.dao.DatasetMapper;
import com.briup.pai.entity.dto.DatasetSaveDTO;
import com.briup.pai.entity.po.Dataset;
import com.briup.pai.entity.vo.*;
import com.briup.pai.service.IClassifyService;
import com.briup.pai.service.IDatasetService;
import com.briup.pai.service.IEntityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class DatasetServiceImpl extends ServiceImpl<DatasetMapper, Dataset> implements IDatasetService {

    @Autowired
    private DatasetConvert datasetConvert;
    @Autowired
    private IClassifyService classifyService;
    @Autowired
    private IEntityService entityService;
    // 定义图片实体保存的路径
    @Value("${upload.nginx-file-path}")
    private String nginxFilePath;

    @Override
    public PageVO<DatasetPageVO> getDatasetByPageAndCondition(Long pageNum, Long pageSize, String datasetName, Integer datasetType) {
        // 添加分页
        Page<Dataset> page = new Page<>(pageNum, pageSize);
        // 查询
        LambdaQueryWrapper<Dataset> lqw = new LambdaQueryWrapper<>();
        lqw.like(Objects.nonNull(datasetName),Dataset::getDatasetName, datasetName)
                .eq(Objects.nonNull(datasetType),Dataset::getDatasetType, datasetType);
        List<Dataset> datasets = this.baseMapper.selectList(page, lqw);
        PageVO<DatasetPageVO> pageVO = new PageVO<>();
        pageVO.setTotal(page.getTotal());
        // 注意需要手动添加分类数量、实体数量、数据集类型从数据字典中匹配
        List<DatasetPageVO> datasetPageVOS = datasetConvert.po2DatasetPageVOList(
                datasets).stream().peek(datasetPageVO -> {
                    // 设置分类数量
                    List<ClassifyInDatasetVO> datasetVOS = classifyService.getClassifiesByDatasetId(datasetPageVO.getDatasetId());
                    datasetPageVO.setClassifyNum((long) datasetVOS.size());
                    // 设置实体数量（遍历获取）
                    long entityNum = 0L;
                    for (ClassifyInDatasetVO classifyInDatasetVO : datasetVOS) {
                        List<EntityInClassifyVO> entityInClassifyVOS = entityService.getEntityByClassifyId(classifyInDatasetVO.getClassifyId());
                        entityNum += entityInClassifyVOS.size();
                    }
                    datasetPageVO.setEntityNum(entityNum);
                }).toList();

        pageVO.setData(datasetPageVOS);

        return pageVO;
    }

    @Override
    @Transactional
    public DatasetEchoVO addOrModifyDataset(DatasetSaveDTO dto) {
        Integer datasetId = dto.getDatasetId();
        System.out.println(dto);
        // 名称、类型、用途不能为空
        BriupAssert.requireNotNull(dto.getDatasetUsage(),ResultCodeEnum.DATA_NOT_EXIST);
        BriupAssert.requireNotNull(dto.getDatasetType(),ResultCodeEnum.DATA_NOT_EXIST);
        BriupAssert.requireNotNull(dto.getDatasetName(),ResultCodeEnum.DATA_NOT_EXIST);
        Dataset dataset = null;
        if(ObjectUtil.isNull(datasetId)){
            // 新增
            // 验证名称必须唯一
            BriupAssert.requireNull(
                    this,
                    Dataset::getDatasetName,
                    dto.getDatasetName(),
                    ResultCodeEnum.DATA_ALREADY_EXIST);
            // DTO-> PO
            dataset = datasetConvert.datasetSaveDTO2Po(dto);
            // 添加少了的东西
            dataset.setDatasetStatus(DatasetStatusEnum.INIT.getStatus());
            // 创建时间和创建人（看一下转换的规则，自动给我们加上了）

            // 保存
            this.save(dataset);
        } else {
            // 更新
            // datasetId必须存在
            Dataset temp = BriupAssert.requireNotNull(
                    this,
                    Dataset::getId,
                    datasetId,
                    ResultCodeEnum.DATA_NOT_EXIST
            );
            // 修改的name必须唯一
            BriupAssert.requireNull(
                    this,
                    Dataset::getDatasetName,
                    dto.getDatasetName(),
                    Dataset::getId,
                    datasetId,
                    ResultCodeEnum.DATA_ALREADY_EXIST
            );
            // 数据类型不能修改
            BriupAssert.requireEqual(
                    dto.getDatasetType(),
                    temp.getDatasetType(),
                    ResultCodeEnum.PARAM_IS_ERROR
            );
            dataset = datasetConvert.datasetSaveDTO2Po(dto);
            this.updateById(dataset);
        }
        // PO -> EchoVO
        return datasetConvert.po2DatasetEchoVO(dataset);
    }

    @Override
    public DatasetEchoVO modifyDatasetFeedback(Integer datasetId) {
        // 验证id存在， 转换输出
        return datasetConvert.po2DatasetEchoVO(
                BriupAssert.requireNotNull(
                this,
                Dataset::getId,
                datasetId,
                ResultCodeEnum.DATA_NOT_EXIST));
    }

    @Override
    public void removeDatasetById(Integer datasetId) {
        // 判断数据集是否存在
        BriupAssert.requireNotNull(
                this,
                Dataset::getId,
                datasetId,
                ResultCodeEnum.DATA_NOT_EXIST);

        // TODO 数据集不能已经用于模型的训练、优化、评估（此功能后续学完模型模块再添加）

        // 删除的时候查询出需要删除的分类和实体
        // 查询出所有的分类id
        List<Integer> classifyIds = classifyService.getClassifiesByDatasetId(datasetId)
                .stream()
                .map(ClassifyInDatasetVO::getClassifyId).toList();
        // 查询所有的实体id
        // 提前准备一个集合，将所有的实体id放到一起
        List<Integer> entityIds = new ArrayList<>();
        for (Integer classifyId : classifyIds) {
            List<Integer> temp = entityService.getEntityByClassifyId(classifyId)
                    .stream()
                    .map(EntityInClassifyVO::getEntityId).toList();
            entityIds.addAll(temp);
        }

        // 删除实体
        entityService.removeBatchByIds(entityIds);
        // 删除分类
        classifyService.removeBatchByIds(classifyIds);
        // 删除数据集
        this.removeById(datasetId);
        // 删除文件
        FileUtil.del(nginxFilePath + "/" +datasetId);
    }

    @Override
    public DatasetDetailVO getDatasetDetail(Integer datasetId) {
        // 验证数据集是否存在
        Dataset dataset = BriupAssert.requireNotNull(
                this,
                Dataset::getId,
                datasetId,
                ResultCodeEnum.DATA_NOT_EXIST);
        // 转换对象
        DatasetDetailVO datasetDetailVO = datasetConvert.po2DatasetDetailVO(dataset);
        // detailVO中还缺一点数据，手动补上
        // 查出所有的分类
        List<ClassifyInDatasetVO> classifies = classifyService.getClassifiesByDatasetId(datasetId);
        datasetDetailVO.setClassifies(classifies);
        datasetDetailVO.setClassifyNum((long) classifies.size());
        // 查询所有的实体，加一下数量
        // 临时变量用来统计
        int num = 0;
        for (ClassifyInDatasetVO tempVo : classifies) {
            List<EntityInClassifyVO> entityInClassifyVOS = entityService.getEntityByClassifyId(tempVo.getClassifyId());
            num += entityInClassifyVOS.size();
        }
        datasetDetailVO.setEntityNum((long) num);
        return datasetDetailVO;
    }
}